# !/usr/bin/env python3

import xlsxwriter
import datetime
import os
import argparse
import logging
import warnings
import json
from PIL import Image, ImageFile

__copyright__ = """
    Copyright Medivh Xu; 
    mailTo:medivh_xu@hotmail.com
"""

LOGGER = logging.getLogger(__name__)

ImageFile.LOAD_TRUNCATED_IMAGES = True  # 防止出现截断图像的错误


class WriteImgForXSLX(object):
    def __init__(self, read_img_path, small_dir_name='small_img', xlsx_file_name='test.xlsx'):
        self._read_img_path = read_img_path
        self._small_dir_name = small_dir_name
        self._xlsx_file_name = xlsx_file_name

    def _check_os_dir(self):
        """
        检测img文件夹及文件夹中的内容、xlsx文件是否存在

        :return:
                _read_dir_name or _small_dir_name：读取图片的文件夹位置
        """

        file1 = os.path.split(self._read_img_path)
        if file1[-1] == '':
            file3 = os.path.split(file1[-2])
            read_file_name = file3[-1]
        else:
            read_file_name = file1[-1]

        assert os.path.isdir(read_file_name), "what?你都没有{}文件夹，我咋给你贴图啊！！！".format(read_file_name)

        all_img = os.listdir(read_file_name)
        assert all_img, "{}文件夹里啥也没有，咋贴！！！".format(read_file_name)

        xls_path = os.path.join(os.getcwd(), self._xlsx_file_name)
        assert os.path.isfile(xls_path), "{}文件不存在！！！".format(self._xlsx_file_name)

        small_img_path = os.path.join(os.getcwd(), self._small_dir_name)
        try:
            if not os.path.isdir(small_img_path):
                os.mkdir(small_img_path, 0o755)
        except Exception as e:
            LOGGER.exception(e)

        if read_file_name == self._small_dir_name:
            LOGGER.warning("读取的文件夹与压缩图片保存的文件夹一致，返回路径:{}".format(self._small_dir_name))
            return self._small_dir_name
        else:
            LOGGER.warning("返回路径:{}".format(read_file_name))
            return read_file_name

    def compression_img(self, height_shrink_multiple=2, width_shrink_multiple=2):
        """
        自动压缩指定文件夹下的所有图片

        :param height_shrink_multiple: 设置图片压缩高度的倍数
        :param width_shrink_multiple: 设置图片压缩宽度的倍数
        :return: True 压缩完成    False 压缩失败
        """

        read_dir_name = self._check_os_dir()

        all_img = os.listdir(read_dir_name)
        for unit_img in all_img:
            try:
                img_num = unit_img.split("-")
                row = int(img_num[0])
                column = int(img_num[1].split(".")[0])
                suffix = (unit_img.split(".")[1])
                if column == 0:
                    LOGGER.warning("图片名称格式有误直接略过！错误文件名：{}，“-”前后数字必须从1开始！".format(unit_img))
                    continue
            except ValueError:
                LOGGER.warning("[-]图片命名规则有误直接略过！错误文件名是：{}".format(unit_img))
                continue

            img_fp = os.path.join(self._read_img_path, unit_img)
            origin_img = Image.open(img_fp)
            w, h = origin_img.size
            small_img = origin_img.resize((int(w / height_shrink_multiple), int(h / width_shrink_multiple)))

            small_img.save(os.path.join(os.getcwd(), "{}/{}-{}.{}".format(self._small_dir_name, row, column, suffix)))
            LOGGER.info(">> 正在处理图像{}-{}.{},原像素宽和高{}，压缩后的宽和高{}".format(row, column, suffix, (w, h), small_img.size))
            try:
                small_img.close()
            except Exception as e:
                LOGGER.debug("未知错误\n{}".format(e))
                return False
        LOGGER.info("--------------图片压缩完成--------------")
        return True

    def write_img_for_xls(self, img_config_set=None, platform='pad', sheet_name="案例截图"):
        """
        读取同目录img文件夹下的所有图片，格式支持png\jpg\bmp。
        图片必须遵从  1-1.png、1-2.png、1-3.png、2-2.png格式...
        注意：是将图片写入新的excel文件，如果老的excel中有数据，将会替换所有数据。

        img_config: {
            "x_scale": 0.29,    # x轴缩放比例
            "y_scale": 0.29,    # y轴缩放比例
            "width": 23.38,     # 图片宽度
            "height": 210.75    # 图片高度
        },
        platform: 选择配置文件中的所写的名称
        sheet_name: 写入excel中sheet的名字

        :return: True 写入成功   False 写入失败
        """

        if img_config_set is None:
            with open('conf.json', 'r', encoding='utf-8') as f:
                conf_dic = json.load(f)
                img_config_set = conf_dic.get(platform)

        check_result = self._check_os_dir()
        LOGGER.info("Read dir is {}".format(check_result))
        xlsx_path = os.path.join(os.getcwd(), self._xlsx_file_name)
        all_img = os.listdir(check_result)
        w_book = xlsxwriter.Workbook(xlsx_path)
        img_sheet = w_book.add_worksheet(name=sheet_name)
        count_num = 0

        try:
            for unit_img in all_img:
                try:
                    img_num = unit_img.split("-")
                    row = int(img_num[0])
                    column = int(img_num[1].split(".")[0])
                    suffix = (unit_img.split(".")[1])
                    if column == 0:
                        LOGGER.warning("图片名称格式有误直接略过！错误文件名：{}，“-”前后数字必须从1开始！".format(unit_img))
                        continue
                except ValueError as e:
                    warnings.warn(e)
                    LOGGER.warning("[-]图片命名规则有误直接略过！错误文件名是：{}".format(unit_img))
                    continue

                LOGGER.info(">> 正在贴图到第{}条用例，第{}列...".format(row, column))
                img_sheet.set_column(first_col=0, last_col=0, width=8.38)
                img_sheet.write(row - 1, 0, "案例{}".format(row))

                small_img = os.path.join(os.getcwd(), "{}/{}-{}.{}".format(check_result, row, column,
                                                                           suffix))

                img_sheet.set_column(first_col=column, last_col=column, width=img_config_set.get("width"))
                img_sheet.set_row(row=row - 1, height=img_config_set.get("height"))

                x_ = img_config_set.get("x_scale")
                y_ = img_config_set.get("y_scale")
                img_config = {"x_scale": x_, "y_scale": y_}

                result = img_sheet.insert_image(row - 1, column, small_img, img_config)
                if not result:
                    LOGGER.info("[+] 写入成功！")
                    count_num += 1
                else:
                    LOGGER.error("[-] 写入失败!")

        except Exception as e:
            LOGGER.exception(e)
            raise MyException("受到不明外力袭击，程序...挂了....\n{}".format(e))
        finally:
            try:
                w_book.close()
            except PermissionError:
                raise MyException("你开着{}文件我让我咋写。。。赶紧关了!".format(self._xlsx_file_name))
        LOGGER.info("程序贴图数量：{}，贴图成功数量：{}，贴图失败数量：{}".format(len(all_img), count_num, len(all_img) - count_num))
        return True


class MyException(Exception):
    pass


if __name__ == '__main__':
    # run
    parser = argparse.ArgumentParser('Sample:  python3 start.py -p ./original_img/ -pl web -a')
    parser.add_argument("-p", help="必须选择图片读取地址")
    parser.add_argument("-pl", help="必须输入平台类型")
    group = parser.add_mutually_exclusive_group()
    group.add_argument("-a", action="store_true", help="压缩图片且贴图到excel")
    group.add_argument("-w", action="store_true", help="直接贴图到excel")
    args = parser.parse_args()

    now = datetime.datetime.now().strftime('%Y-%m-%d_%H_%M_%S')
    log_fp = "./logs/" + now + ".log"
    logging.basicConfig(level=logging.DEBUG,
                        format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                        datefmt='%a, %d %b %Y %H:%M:%S',
                        filename=log_fp,
                        filemode='w')

    console = logging.StreamHandler()
    console.setLevel(logging.INFO)
    formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
    console.setFormatter(formatter)
    logging.getLogger('').addHandler(console)

    LOGGER.info(">>> 选择平台为: {}".format(args.pl))
    with open('conf.json', 'r') as f:
        conf_dic = json.load(f)
        if args.pl not in conf_dic:
            LOGGER.info('[-] 没找到配置信息名称为: {}!'.format(args.pl))
            raise MyException('没找到配置信息名称为: {}!'.format(args.pl))

    run = WriteImgForXSLX(read_img_path=args.p)

    if args.a:
        LOGGER.info(">>> 选择参数-a,即压缩图片，又贴图。")
        c = run.compression_img()
        if c:
            v = run.write_img_for_xls(platform=args.pl)
            if v:
                LOGGER.info("--------------贴图完成--------------")
    elif args.w:
        LOGGER.info(">>> 选择参数-w,只贴图。")
        v = run.write_img_for_xls(platform=args.pl)
        if v:
            LOGGER.info("--------------贴图完成--------------")
    else:
        LOGGER.error("参数错误！")

    # debug
    # run = WriteImgForXSLX(read_img_path='./original_img/')
    # run.compression_img()
    # run.write_img_for_xls(platform='web')
